package com.dcivision.webdav.util;

import java.net.MalformedURLException;
import java.net.URL;

/**
 * This is for the HTTP URL of the generic URI version.
 *
 * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
 */
public class HttpURL
    extends GenericURI {

  // --------------------------------------------------------- Constructors

  /**
   * This Constructor
   *
   * @param escapedHttpURL The escaped http URL string.
   */
  public HttpURL(String escapedHttpURL) {
    super(escapedHttpURL);
    setDefaultScheme(scheme);
    setDefaultPort(port);
  }

  /**
   * This Constructor
   *
   * @param host The host string.
   * @param path The path string.
   */
  public HttpURL(String host, String path) {
    this(null, null, host, HttpURL.port, path, null);
  }

  /**
   * This Constructor
   *
   * @param host The host string.
   * @param port The port number.
   * @param path The path string.
   */
  public HttpURL(String host, int port, String path) {
    this(null, null, host, port, path, null);
  }

  /**
   * This Constructor
   *
   * @param host The host string.
   * @param port The port number.
   * @param path The path string.
   * @param query The query string.
   */
  public HttpURL(String host, int port, String path, String query) {
    this(null, null, host, port, path, query);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   */
  public HttpURL(String userName, String password, String host) {
    this(userName, password, host, HttpURL.port, null, null);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   * @param port The port number.
   */
  public HttpURL(String userName, String password, String host, int port) {
    this(userName, password, host, port, null, null);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   * @param path The path string.
   */
  public HttpURL(String userName, String password, String host,
                 String path) {
    this(userName, password, host, HttpURL.port, path, null);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   * @param port The port number.
   * @param path The path string.
   */
  public HttpURL(String userName, String password, String host, int port,
                 String path) {
    this(userName, password, host, port, path, null);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   * @param path The path string.
   * @param query The query string.
   */
  public HttpURL(String userName, String password, String host,
                 String path, String query) {
    this(userName, password, host, HttpURL.port, path, query);
  }

  /**
   * This Constructor
   *
   * @param userName The username string.
   * @param password The password string.
   * @param host The host string.
   * @param port The port number.
   * @param path The path string.
   * @param query The query string.
   */
  public HttpURL(String userName, String password, String host, int port,
                 String path, String query) {

    super
        (URIUtil.escape(HttpURL.scheme, URIUtil.schemeReserved()) + "://" +
         ( (userName == null) ? "" :
          URIUtil.escape(userName) + ( (password == null) ? "" :
                                      ":" + URIUtil.escape(password))
          + "@") +
         URIUtil.escape(host, URIUtil.hostReserved()) +
         ( (port == HttpURL.port || port == -1) ? "" : ":" + port) +
         ( (path == null || path.equals("")) ? "/" :
          URIUtil.escape( (!path.startsWith("/")) ?
                         "/" + path : path, URIUtil.pathReserved())) +
         ( (query == null || query.equals("")) ? "" :
          "?" + URIUtil.escape(query, URIUtil.queryReserved())));
    setDefaultScheme(scheme);
    setDefaultPort(port);
  }

  /**
   * This Constructor
   *
   * @param httpURL The http URL.
   * @param path The added relative path.
   */
  public HttpURL(HttpURL httpURL, String path) {

    this(httpURL.toString() +
         (httpURL.toString().endsWith("/") ? "" : "/") +
         URIUtil.escape(path, URIUtil.pathReserved()));
  }

  // ------------------------------------------------------------ Constants

  /**
   * Default scheme for HTTP URL.
   */
  public final static String scheme = "http";

  /**
   * Default port for HTTP URL.
   */
  public final static int port = 80;

  /**
   * The serialVersionUID.
   */
  static final long serialVersionUID = -7158031098595039458L;

  // ---------------------------------------------------  Protected methods

  /**
   * Get the scheme for the http URL.
   *
   * @return The scheme for the http URL.
   */
  protected String getDefaultScheme() {
    return scheme;
  }

  /**
   * Get the default port number for the http URL.
   *
   * @return The port number to set for the http URL.
   */
  protected int getDefaultPort() {
    return port;
  }

  // ------------------------------------------------------  Public Methods

  /**
   * Get the userinfo part for this http URL.
   *
   * @return The userifno of this http URL.
   * @exception MalformedURLException
   */
  public String getUserInfo() throws MalformedURLException {

    return getUserInfo(getEscapedURI());
  }

  /**
   * Get the escaped userinfo part for this http URL.
   *
   * @return The escaped userifno of this http URL.
   * @exception MalformedURLException
   */
  public String getEscapedUserInfo() throws MalformedURLException {

    return getEscapedUserInfo(getEscapedURI());
  }

  /**
   * Get the userinfo part of the given escaped URI string.
   *
   * @param escapedURI The escaped URI string to get the userinfo part.
   * @return The userifno of the given URI.
   * @exception MalformedURLException
   */
  public static String getUserInfo(String escapedURI) throws
      MalformedURLException {

    return URIUtil.unescape(getEscapedUserInfo(escapedURI));
  }

  /**
   * Get the escaped userinfo part of the given escaped URI string.
   *
   * @param escapedURI The escaped URI string to get the userinfo part.
   * @return The userifno of the given URI.
   * @exception MalformedURLException
   */
  public static String getEscapedUserInfo(String escapedURI) throws
      MalformedURLException {

    String authority = getEscapedAuthority(escapedURI);
    int to = authority.lastIndexOf("@");

    return (to > 0) ? authority.substring(0, to) : null;
  }

  /**
   * Set the username and password for this URI.
   *
   * @param userName The username string.
   * @param password The password string.
   * @exception MalformedURLException
   */
  public void setUserInfo(String userName, String password) throws
      MalformedURLException {

    setEscapedURI(getEscapedScheme() + "://" +
                  ( (userName == null) ? "" : URIUtil.escape(userName) +
                   ( (password == null) ? "" : ":" +
                    URIUtil.escape(password)) + "@") +
                  getEscapedHostPort() + getEscapedPathQuery());
  }

  /**
   * Get the username on the userinfo for this http URL.
   *
   * @return The username of URI
   * @exception MalformedURLException
   * @see #getUserName(java.lang.String)
   */
  public String getUserName() throws MalformedURLException {

    return getUserName(getEscapedURI());
  }

  /**
   * Get the username on the userinfo of the given URI string.
   *
   * @param escapedURI The escaped URI string to get the username.
   * @return The username of URI
   * @exception MalformedURLException
   */
  public static String getUserName(String escapedURI) throws
      MalformedURLException {

    try {
      String userInfo = getEscapedUserInfo(escapedURI);
      int to = userInfo.indexOf(":");

      String username = (to > 0) ? userInfo.substring(0, to) : userInfo;
      return URIUtil.unescape(username);
    }
    catch (NullPointerException npe) {
      // No userinfo
      return null;
    }
  }

  /**
   * Get the password on the userinfo for this URI string.
   *
   * @return The password of URI
   * @exception MalformedURLException
   */
  public String getPassword() throws MalformedURLException {

    return getPassword(getEscapedURI());
  }

  /**
   * Get the password on the userinfo of the given URI string.
   *
   * @param escapedURI The escaped URI string to get the password.
   * @return The password of URI
   * @exception MalformedURLException
   */
  public static String getPassword(String escapedURI) throws
      MalformedURLException {

    try {
      String userInfo = getEscapedUserInfo(escapedURI);
      int at = userInfo.indexOf(":");

      String password = (at >= 0) ? userInfo.substring(at + 1) : null;
      return URIUtil.unescape(password);
    }
    catch (NullPointerException npe) {
      // No userinfo
      return null;
    }
  }

  // ------------------------------------------------------- Utility Methods

  /**
   * Get the parent path for this http URL.
   * This method ignores the forward part of the http URL.
   *
   * @return The parent path of the given already-normalized path.
   */
  public String getParent() {

    return getParent(getEscapedURI());
  }

  /**
   * Get the parent path of the given already-normalized path.
   * This method ignores the forward part of the http URL.
   *
   * @param escapedPath The escaped path string.
   * @return The parent path of the given already-normalized path.
   */
  public static String getParent(String escapedPath) {

    String pathname = getPath(escapedPath);

    if (pathname.endsWith("/")) {
      int at = pathname.lastIndexOf("/");
      // consider of root pathname
      if (at > 0) {
        pathname = pathname.substring(0, at);
        at = pathname.lastIndexOf("/");
        pathname = pathname.substring(0, at + 1);
      }
    }
    else {
      int at = pathname.lastIndexOf("/");
      pathname = pathname.substring(0, at + 1);
    }

    return URIUtil.unescape(pathname);
  }

  /**
   * Get the resource or collection name for this http URL.
   *
   * @return The resource or collection name string for this http URL.
   */
  public String getName() {
    return getName(getEscapedURI());
  }

  /**
   * Get the resource or collection name of the already-normalized path.
   *
   * @param escapedPath The already-normalized path.
   * @return The collection name, if the path is a collection,
   *         The resource name, if the path is a resource.
   */
  public static String getName(String escapedPath) {

    // Return a string starting with the '/' charcater.
    String name = getPath(escapedPath);
    // For the root path.
    if (name.equals("/")) {
      return name;
    }
    // Remove the last '/' character.
    if (name.endsWith("/")) {
      name = name.substring(0, name.length() - 1);

    }
    return URIUtil.unescape(name.substring(name.lastIndexOf("/") + 1));
  }

  /**
   * Get the HttpURL instance.
   *
   * @return The http URL.
   */
  public HttpURL getHttpURL() {
    return new HttpURL(getEscapedURI());
  }

  /**
   * Get the escaped http URL string.
   *
   * @return The escaped http URL string.
   */
  public String getEscapedHttpURL() {
    return getHttpURL().toString();
  }

  /**
   * Get the http URL string.
   *
   * @return The http URL string.
   */
  public String getUnescapedHttpURL() {
    return URIUtil.unescape(getHttpURL().toString());
  }

  /**
   * Get the HttpURL instance except for password.
   *
   * @return The http URL except for password.
   */
  public HttpURL getHttpURLExceptForPassword() throws MalformedURLException {

    HttpURL httpURL = getHttpURL();
    httpURL.setUserInfo(httpURL.getUserName(), null);

    return httpURL;
  }

  /**
   * Get the escaped HttpURL string except for password.
   *
   * @return The escaped http URL string except for password.
   */
  public String getEscapedHttpURLExceptForPassword() throws
      MalformedURLException {

    return getHttpURLExceptForPassword().toString();
  }

  /**
   * Get the HttpURL string except for password.
   *
   * @return The http URL string except for password.
   */
  public String getUnescapedHttpURLExceptForPassword() throws
      MalformedURLException {

    return URIUtil.unescape(getHttpURLExceptForPassword().toString());
  }

  /**
   * Get the HttpURL instance except for userinfo.
   *
   * @return The http URL except for password.
   */
  public HttpURL getHttpURLExceptForUserInfo() throws MalformedURLException {

    HttpURL httpURL = getHttpURL();
    httpURL.setUserInfo(null, null);

    return httpURL;
  }

  /**
   * Get the escaped HttpURL string except for userinfo.
   *
   * @return The escaped http URL string except for password.
   */
  public String getEscapedHttpURLExceptForUserInfo() throws
      MalformedURLException {

    return getHttpURLExceptForUserInfo().toString();
  }

  /**
   * Get the HttpURL string except for userinfo.
   *
   * @return The http URL string except for password.
   */
  public String getUnescapedHttpURLExceptForUserInfo() throws
      MalformedURLException {

    return URIUtil.unescape(getHttpURLExceptForUserInfo().toString());
  }

  /**
   * To support <code>java.net.URL</code> of JDK 1.1.x.
   *
   * @return <code>java.net.URL</code>
   * @exception MalformedURLException
   */
  public URL toURL() throws MalformedURLException {

    return new URL(getUnescapedHttpURLExceptForUserInfo().toString());
  }

}
